home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / manage / snmp / kip / gw2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-01-17  |  18.0 KB  |  850 lines

  1. /*
  2.  * AppleTalk / Ethernet Gateway;  part 2.
  3.  *
  4.  * (c) 1986, Stanford Univ. CSLI.
  5.  * May be used but not sold without permission.
  6.  *
  7.  * $Header: gw2.c,v 4.1 88/11/01 19:49:25 sw0l Locked $
  8.  */
  9.  
  10. #include "gw.h"
  11. #include "gwctl.h"
  12. #include "fp/pbuf.h"
  13. #include "ab.h"
  14. #include "inet.h"
  15. #include "fp/cmdmacro.h"
  16. #ifdef SNMP
  17. #include "snmp.h"
  18. #include "mib.h"
  19. #include "snmp_vars.h"
  20. #endif
  21.  
  22. #include "glob.h"
  23.  
  24. /*
  25.  * NBP packet input from appletalk (abreceive).
  26.  */
  27. nbpinput(p)
  28.     struct pbuf *p;
  29. {
  30.     register struct NBP *n = (struct NBP *)(p->p_off + lapSize + ddpSize);
  31.     register op = (n->control & nbpControlMask);
  32.     Entity ent;
  33.     register iaddr;
  34.  
  35.     /*
  36.      * if bridge request, put on backround queue
  37.      * to nbpback, who will send all the LkUp's.
  38.      */
  39.     if (op == nbpBrRq) {
  40.         K_PENQNP(&nbpq, p);
  41.         return;
  42.     }
  43.     /* else packet is a LkUp or LkUpReply, check for local names */
  44.     nbpgetent(n->tuple.name, &ent);    /* break up tuple name entity */
  45.     /*
  46.      * if lookup reply for us, complete any pending requests.
  47.      */
  48.     if (op == nbpLkUpReply) {
  49.         if (ddp.dstNode != ifab.if_dnode
  50.             || strcmp(ent.type, "IPADDRESS") != 0
  51.             || (iaddr = atoip(ent.obj, 99)) == 0 )
  52.             goto drop;
  53.         /* pass the address reply to ARP and ipdad modules */
  54.         arpgotreply(&ifab, iaddr, &n->tuple.addr);
  55.         ipdadreply(&ifab, iaddr, &n->tuple.addr);
  56.         goto drop;
  57.     }
  58.     /*
  59.      * else lookup;  handle requests for our IP related services.
  60.      */
  61.     if (strcmp(ent.type, "IPGATEWAY") == 0) {
  62.         iaddr = conf.ipaddr;
  63.         goto replyus;
  64.     }
  65.     if (strcmp(ent.type, "IPADDRESS") == 0) {
  66.         if ((iaddr = atoip(ent.obj, 99)) == 0
  67.             || ipbroadcast(iaddr))
  68.             goto drop;    /* dont reply to bad addresses */
  69.         if (abmatch(iaddr))
  70.             goto replyus;
  71.     }
  72.     if (strcmp(ent.type, "=") == 0 && strcmp(ent.obj, "=") == 0) {
  73.         iaddr = conf.ipaddr;
  74.         strcpy(ent.type, "IPGATEWAY");
  75.         goto reply;
  76.     }
  77.     goto drop;
  78. replyus:
  79.     if (getaroute(n->tuple.addr.net) == 0)
  80.         goto drop;    /* not our responsibility */
  81. reply:
  82.     iptoa(iaddr, ent.obj);
  83.     /* Should always return with "my zone" */
  84.     ddp.length = nbpsetent(n->tuple.name, ent.obj, ent.type, "*")
  85.         + ddpSize + nbpMinSize;
  86.     ddp.checksum = 0;
  87.     ddp.srcNet = source_if->if_dnet;
  88.     ddp.srcNode = source_if->if_dnode;
  89.     ddp.dstNet = n->tuple.addr.net;
  90.     ddp.dstNode = n->tuple.addr.node;
  91.     ddp.dstSkt = n->tuple.addr.skt;
  92.     n->tuple.addr.net = ddp.srcNet;
  93.     n->tuple.addr.node = ddp.srcNode;
  94.     n->tuple.addr.skt = ddpIPSkt;
  95.     ddp.srcSkt = nbpNIS;
  96.     n->control = nbpLkUpReply + 1;
  97.     p->p_len = ddp.length + lapSize;
  98.     bcopy((caddr_t)&ddp, p->p_off+lapSize, ddpSize);
  99.     routeddp(p, 0, 0);
  100.     return;
  101. drop:
  102.     K_PFREE(p);
  103. }
  104.  
  105.  
  106. /*
  107.  * Queue an NBP lookup request.  If net/node is non-zero,
  108.  * does an 'nbpconfirm' operation.
  109.  */
  110. nbplookup(ent, net, node)
  111.     Entity *ent;
  112. {
  113.     register struct NBP *n;
  114.     register struct pbuf *p;
  115.     struct DDP d;
  116.  
  117.     K_PGET(PT_DATA, p);
  118.     if (p == 0)
  119.         return;
  120.     n = (struct NBP *)(p->p_off + lapSize + ddpSize);
  121.     n->control = nbpLkUp + 1;
  122.     n->id = 0;
  123.     n->tuple.enume = 0;
  124.     n->tuple.addr.net = d.srcNet = ifab.if_dnet;
  125.     n->tuple.addr.node = d.srcNode = ifab.if_dnode;
  126.     n->tuple.addr.skt = d.srcSkt = d.dstSkt = nbpNIS;
  127.     d.checksum = 0;
  128.     d.type = ddpNBP;
  129.     d.length = nbpsetent(n->tuple.name, ent->obj, ent->type, ent->zone)
  130.         + ddpSize + nbpMinSize;
  131.     p->p_off[2] = lapDDP;
  132.     p->p_len = d.length + lapSize;
  133.     if (net) {    /* wants an nbpconfirm */
  134.         d.dstNet = net;
  135.         d.dstNode = node;
  136.     }
  137.     bcopy((caddr_t)&d, p->p_off + lapSize, ddpSize);
  138.     if (net) {
  139.         bcopy((caddr_t)&d, (caddr_t)&ddp, ddpSize);
  140.         routeddp(p, 0, 0);
  141.     } else {
  142.         K_PENQNP(&nbpq, p);
  143.     }
  144. }
  145.  
  146.  
  147. /* 'static' */
  148. struct aroute *nback_arfrom;
  149. struct aroute *nback_arnext;
  150. short nback_zoneindex;
  151.  
  152. /*
  153.  * NBP 'backround'.  Check nbpq for BrRq's to be sent out as LkUp's.
  154.  * Sends to one net per call/loop.
  155.  */
  156. nbpback()
  157. {
  158.     register struct aroute *ar, *arx;
  159.     register struct pbuf *pq, *p;
  160.     struct NBP *n;
  161.     register int zi;
  162.     u_char i;
  163.     u_char *zone;
  164.  
  165.     if ((pq = nbpq.pq_head) == 0)
  166.         return;        /* if nothing to do */
  167.     if (sendq->pq_head)
  168.         return;        /* delay if ether sendq exists */
  169.  
  170.     if ((ar = nback_arnext) == 0) {    /* first time for this packet */
  171.         ar = nback_arnext = &aroute[0];
  172.         bcopy(pq->p_off + lapSize, (caddr_t)&ddp, ddpSize);
  173.         ddp.checksum = 0;
  174.         ddp.dstNode = 0xFF;    /* dstNet set below */
  175.         n = (struct NBP *)(pq->p_off + lapSize + ddpSize);
  176.         n->control = nbpLkUp + 1;
  177.         zi = n->tuple.name[0] + 1; /* skip name */
  178.         /* should check to see if we are off end of pkt */
  179.         if (zi > 33)
  180.           goto drop;
  181.         if (n->tuple.name[zi] > 32)
  182.           goto drop;
  183.         zi += n->tuple.name[zi] + 1; /* skip type */
  184.         zone = &n->tuple.name[zi]; /* zone length + zone */
  185.         if (zone[0] > 32)
  186.           goto drop;
  187.         /* find route */
  188.         for (arx = &aroute[0]; arx < &aroute[NAROUTE]; ++arx)
  189.           if (arx->net == ddp.srcNet)
  190.             break;
  191.         /* forget it if we can't figure out where it came from */
  192.         if (arx >= &aroute[NAROUTE])
  193.           goto drop;
  194.         /* Translate '*' to my zone */
  195.         if (zone[0] == 1  && zone[1] == '*') {
  196.           /* Choose the zone for the interface message came from */
  197.           if (arx->zone == 0)
  198.             goto drop;
  199.           i = azone[arx->zone][0]+1;
  200.           bcopy(azone[arx->zone], zone, i);
  201.           i -= 2;    /* -2 for '\01*' */
  202.           pq->p_len += i;
  203.           ddp.length += i;
  204.         }
  205.         nback_arfrom = arx;
  206.         /* copy deferred from above so we can reset ddp length */
  207.         bcopy((caddr_t)&ddp, pq->p_off + lapSize, ddpSize);
  208.         if ((nback_zoneindex = zipfind(zone, 1)) == -1)
  209.             goto drop;
  210.     }
  211.     n = (struct NBP *)(pq->p_off + lapSize + ddpSize);
  212.     /*
  213.      * for each net, route a packet there 
  214.      */
  215.     for ( ; ar < &aroute[NAROUTE] ; ++ar) {
  216.         if (ar->net == 0)
  217.             continue;
  218.         /* continue if wrong zone and the zone is not all zones */
  219.         /* make sure allzones is set before using */
  220.         if (ar->zone != nback_zoneindex &&
  221.             !(allzones && ar->zone == allzones))
  222.           continue;
  223.         K_PGET(PT_DATA, p);
  224.         if (p == 0)
  225.             return;    /* try later */
  226.         /* copy efficiently in 4 byte (long) chunks */
  227.         bcopy(pq->p_off, p->p_off, ((pq->p_len + 3) & 0xFFFC));
  228.         p->p_len = pq->p_len;
  229.         /*
  230.          * Set the net number directly into the ddp header,
  231.          * without copying.  Setup a few ddp.xxx globals for
  232.          * the convenience of 'routeddp'.
  233.          */
  234.         p->p_off[7] = (ar->net >> 8);
  235.         p->p_off[8] = ar->net;
  236.         ddp.srcNet = nback_arfrom->net;
  237.         ddp.dstNet = ar->net;
  238.         ddp.dstNode = 0xFF;
  239.         ddp.dstSkt = ddp.srcSkt = nbpNIS;
  240.         routeddp(p, porttoif[nback_arfrom->port], 0);
  241.         nback_arnext = ar + 1;
  242.         return;
  243.     }
  244. drop:
  245.     /* done with this BrRq, dequeue it */
  246.     K_PDEQNP(&nbpq, pq);
  247.     K_PFREE(pq);
  248.     nback_arnext = 0;
  249. }
  250.  
  251.  
  252. /*
  253.  * Ask "who has" IP address addr, using NBP on my locally
  254.  * connected segments.
  255.  */
  256. nbpwhohasip(addr)
  257.     iaddr_t addr;
  258. {
  259.     Entity ent;
  260.  
  261.     iptoa(addr, ent.obj);
  262.     strcpy(ent.zone, "*");
  263.     strcpy(ent.type, "IPADDRESS");
  264.     nbplookup(&ent, 0, 0);
  265. }
  266.  
  267.  
  268. /*
  269.  * Unpack an nbp entity starting at cp.
  270.  * Returns total size of entity (for skipping to next tuple).
  271.  */
  272. nbpgetent(cp, ent)
  273.     register char *cp;
  274.     register Entity *ent;
  275. {
  276.     char *oldcp;
  277.     register i;
  278.  
  279.     oldcp = cp;
  280.     i = (*cp & 0x1F); bcopy(cp+1, ent->obj, i); ent->obj[i] = 0; cp += i+1;
  281.     i = (*cp & 0x1F); bcopy(cp+1, ent->type, i); ent->type[i] = 0; cp += i+1;
  282.     i = (*cp & 0x1F); bcopy(cp+1, ent->zone, i); ent->zone[i] = 0; cp += i+1;
  283.     return (cp - oldcp);
  284. }
  285.  
  286.  
  287. /*
  288.  * Setup an nbp entity field with object, type, and zone strings.
  289.  * Returns length of this tuple.
  290.  */
  291. nbpsetent(cp, obj, type, zone)
  292.     register char *cp;
  293.     char *obj, *type, *zone;
  294. {
  295.     register char *oldcp = cp;
  296.     register i;
  297.  
  298.     *cp = i = strlen(obj);  bcopy(obj, cp+1, i);  cp += i+1;
  299.     *cp = i = strlen(type);  bcopy(type, cp+1, i);  cp += i+1;
  300.     *cp = i = strlen(zone);  bcopy(zone, cp+1, i);  cp += i+1;
  301.     return (cp - oldcp);
  302. }
  303.  
  304.  
  305. /*
  306.  * Filter out certain NBP lookup replies to provide (some)
  307.  * security for LaserWriter and other servers outside the local zone.
  308.  */
  309. nbpfilter(p)
  310.     struct pbuf *p;
  311. {
  312.     register struct NBP *n = (struct NBP *)(p->p_off + lapSize + ddpSize);
  313.     register u_char *cp;
  314.     register i,j;
  315.     register struct aroute *ar;
  316.     char filter = 0;
  317.  
  318.     if ((n->control & nbpControlMask) != nbpLkUpReply)
  319.         return (0);
  320.     cp = n->tuple.name;
  321.     if (conf.flags & conf_tildefilter) {
  322.         i = *cp;
  323.         if (cp[i] == '~')
  324.             filter++;
  325.     }
  326.     if(conf.flags & conf_laserfilter) {
  327.         cp += *cp + 1;
  328.         if (*cp == 11 && strncmpci(cp+1, "LaserWriter", 11) == 0)
  329.             filter++;
  330.     }
  331.     if (filter == 0)
  332.         return (0);
  333.     /*
  334.      * if srcNet is in my zone but dstNet is not,
  335.      * drop it.
  336.      */
  337.     i = j = 0;
  338.     for (ar = &aroute[0] ; ar < &aroute[NAROUTE] ; ++ar) {
  339.         if (ar->net == ddp.srcNet)
  340.             i = ar->zone;
  341.         if (ar->net == ddp.dstNet)
  342.             j = ar->zone;
  343.         if (i && j)
  344.             break;
  345.     }
  346.     if (i != aroute[0].zone)
  347.         return (0);
  348.     if (j == i)
  349.         return (0);
  350.     return (1);        /* drop it */
  351. }
  352.  
  353.  
  354. /*
  355.  * Process an IP packet directed to the gateway's own IP address.
  356.  * These are usually control packets such as admin configure/
  357.  * net table, debug packets, ICMP packets.
  358.  */
  359. ip4me(p)
  360.     struct pbuf *p;
  361. {
  362.     register struct ip *ip = (struct ip *)p->p_off;
  363.     int hlen = ip->ip_hl << 2;
  364.     struct udp *u;
  365.     register struct gwdb *g;
  366.     register struct aaconf *m;
  367.     struct icmp *ic;
  368.  
  369.     if (ip->ip_p == IPPROTO_ICMP)
  370.         goto icmp;
  371.     if (ip->ip_p == IPPROTO_UDP)
  372.         goto udp;
  373. #ifdef SNMP
  374.     mib_ip.ipInUnknownProtos++;
  375. #endif
  376. drop:
  377.     K_PFREE(p);
  378.     return;
  379. udp:
  380. #ifdef SNMP
  381.     mib_ip.ipInDelivers++;
  382. #endif
  383.     u = (struct udp *)(p->p_off + hlen);
  384.     switch (u->dst) {
  385.     case aaPort:
  386. #ifdef SNMP
  387.         mib_udp.udpInDatagrams++;
  388. #endif
  389.         m = (struct aaconf *)(u+1);
  390.         /* this may be too inflexible, but so be it */
  391.         if (m->magic != aaMagic || ipRus(ip->ip_src) == 0)
  392.             goto drop;    /* not from our friends */
  393.         switch (m->type) {
  394.         case aaCONF:
  395.             confready(m);
  396.             break;
  397.  
  398.         case aaROUTEI:
  399.             azoneinit = 0; /* need to fetch zone info */
  400.         case aaROUTE:
  401.         case aaROUTEQ:
  402.             artinput(m, ip->ip_src);
  403.             break;
  404.  
  405.         case aaRESTART:
  406.             K_EXECUTE();
  407.             break;
  408. #ifdef notdef
  409.         case aaZONE:
  410.             zipinit(m);
  411.             break;
  412. #endif
  413.         case aaZONEQ:
  414.             zipinput(m->stuff,(int)m->count, ip->ip_src);
  415.             break;
  416.         }
  417.         goto drop;
  418.  
  419.     case gwdbPort:
  420. #ifdef SNMP
  421.         mib_udp.udpInDatagrams++;
  422. #endif
  423.         goto gwdb;
  424.  
  425.     case rebPort:
  426. #ifdef SNMP
  427.         mib_udp.udpInDatagrams++;
  428. #endif
  429.         if (ip->ip_dst != conf.ipaddr)
  430.             goto drop;
  431.         bcopy((caddr_t)(u+1) + lapSize, &ddp, ddpSize);
  432.         p->p_off += hlen + sizeof *u;
  433.         p->p_len -= hlen + sizeof *u;
  434.         routeddp(p, 0, 0);
  435.         return;
  436. #ifdef SNMP
  437.     case SNMP_PORT:
  438.         mib_udp.udpInDatagrams++;
  439.         snmp_input(p);
  440.         goto drop;
  441.     default:
  442.         mib_udp.udpNoPorts++;
  443. #endif SNMP
  444.     }
  445.     goto drop;
  446. gwdb:
  447.     g = (struct gwdb *)(u+1);
  448.     if (ip->ip_src != conf.ipdebug || g->magic != gwdbMagic)
  449.         goto drop;
  450.     switch (g->op) {
  451.     case gwdbRead:
  452.         bcopy(g->address, g->data, g->count);
  453.         break;
  454.  
  455.     case gwdbWrite:
  456.         bcopy(g->data, g->address, g->count);
  457.         break;
  458.  
  459.     default:
  460.         g->op = 0;    /* error reply code */
  461.     }
  462.     /*
  463.      * Assume the packet length does not change.
  464.      */
  465.     u->checksum = 0;
  466. #ifdef SNMP
  467.     mib_udp.udpOutDatagrams++;
  468. #endif
  469. flip:
  470.     ip->ip_dst = ip->ip_src;
  471.     ip->ip_src = conf.ipaddr;
  472.     ip->ip_sum = 0;
  473.     ip->ip_sum = in_cksum((caddr_t)ip, hlen);
  474.     routeip(p, 0, 0);
  475.     return;
  476. icmp:
  477. #ifdef SNMP
  478.     mib_ip.ipInDelivers++;
  479.     mib_icmpInMsgs++;
  480. #endif
  481.     ic = (struct icmp *)(p->p_off + hlen);
  482. #ifdef SNMP
  483.     mib_icmpInCount[ic->icmp_type]++;
  484. #endif
  485.     if (ic->icmp_type == ICMP_ECHO) {
  486.         ic->icmp_type = ICMP_ECHOREPLY;
  487.         ic->icmp_cksum = 0;
  488.         ic->icmp_cksum = in_cksum((caddr_t)ic, ip->ip_len - hlen);
  489. #ifdef SNMP
  490.         mib_icmpOutCount[ic->icmp_type]++;
  491.         mib_icmpOutMsgs++;
  492. #endif
  493.         goto flip;
  494.     }
  495.     goto drop;
  496. }
  497.  
  498.  
  499. /*
  500.  * IP are us.  Returns true if this IP address is 'one of us':
  501.  * the administrator or one of the configured gateways.
  502.  */
  503. ipRus(ia)
  504.     iaddr_t ia;
  505. {
  506.     register struct aroute *ar;
  507.     register f;
  508.  
  509.     f = (arouteKbox|arouteAA);
  510.     if (ia == conf.ipadmin || ia == conf.ipdebug)
  511.         return (1);
  512.     for (ar = &aroute[0] ; ar < &aroute[NAROUTE] ; ++ar) {
  513.         if (ar->net == 0)
  514.             continue;
  515.         if ((ar->flags & f) != f)
  516.             continue;
  517.         if (ar->node == ia)
  518.             return (1);
  519.     }
  520.     return (0);
  521. }
  522.  
  523. /*
  524.  * Process a DDP packet directed to the gateway's own address.
  525.  * Called from routeddp with the ddp header already unpacked
  526.  * in global struct 'ddp'.
  527.  */
  528. ddp4me(p)
  529.     register struct pbuf *p;
  530. {
  531.     register struct ATP *a;
  532.     register struct IPGP *ig;
  533.  
  534.     switch (ddp.type) {
  535.     case ddpNBP:
  536.       if (ddp.dstSkt != nbpNIS)
  537.         goto drop;
  538.       nbpinput(p);
  539.       return;
  540.     case ddpRTMP:
  541.     case ddpRTMPR:
  542.       if (ddp.dstSkt != rtmpSkt)
  543.         goto drop;
  544.       rtmpinput(p);
  545.       return;
  546.     case ddpECHO:
  547.       if (ddp.dstSkt != echoSkt)
  548.         goto drop;
  549.       if (p->p_off[lapSize+ddpSize] != echoRequest) 
  550.         goto drop;
  551.       p->p_off[lapSize+ddpSize] = echoReply;
  552.       ddpreply(p, echoSkt);
  553.       return;
  554.     case ddpZIP:
  555.       if (ddp.dstSkt == zipSkt)
  556.         zipinput(p->p_off+lapSize+ddpSize, p->p_len-lapSize-ddpSize,0L);
  557.       goto drop;
  558.     case ddpATP:
  559.       if (ddp.dstSkt == zipSkt) {
  560.         zipatp(p);
  561.         return;
  562.       }
  563.       if (ddp.dstSkt != ddpIPSkt)
  564.         goto drop;
  565.       break;
  566.     default:
  567.       goto drop;
  568.     }
  569.     a = (struct ATP *)(p->p_off + lapSize + ddpSize);
  570.     if ((ddp.length & ddpLengthMask) < (ddpSize + sizeof *a + 4))
  571.         goto drop;
  572.     if ((a->control & (~atpFlagMask)) != atpReqCode)
  573.         goto drop;
  574.     ig = (struct IPGP *)(a + 1);
  575.     switch (ig->op) {
  576.     case ipgpAssign:
  577.     case ipgpServer:
  578.         ipgassign(ig, ig->op);
  579.         break;
  580.  
  581.     /* case ipgpName:
  582.         ipgname(ig);
  583.         goto drop;*/
  584.  
  585.     default:
  586.         strcpy(ig->string, "bad op");
  587.         ig->op = -1;
  588.         break;
  589.     }
  590.     a->control = atpRspCode + atpEOM;
  591.     a->bitmap = 0;
  592.     /* +1 is to account for null */
  593.     p->p_len=lapSize+ddpSize+sizeof(*a)+ipgpMinSize+strlen(ig->string)+1;
  594.     ddpreply(p, ddpIPSkt);
  595.     return;
  596. drop:
  597.     K_PFREE(p);
  598. }
  599.  
  600.  
  601. /*
  602.  * IPGATEWAY request to assign address.
  603.  */
  604. ipgassign(ig, op)
  605.     register struct IPGP *ig;
  606. {
  607.     register struct ipdad *d;
  608.     struct ipdad *od;
  609.     int dmax, otimer;
  610.     register i;
  611.  
  612.     if (op == ipgpServer)
  613.         goto server;    /* skip most of this */
  614.     dmax = conf.ipdynamic;
  615.     otimer = 0;
  616.     for (d = &ipdad[0], i = 0 ; i < dmax ; d++,i++ ) {
  617.         if (d->timer == 0) {
  618.             otimer = ipdadTimerMax;
  619.             od = d;
  620.         } else if (d->timer > otimer) {
  621.             otimer = d->timer;
  622.             od = d;
  623.         }
  624.         if (d->net == ddp.srcNet && d->node == ddp.srcNode)
  625.             goto assign;
  626.     }
  627.     if (otimer <= ipdadTimerMin) {
  628.         ig->op = -1;
  629.         strcpy(ig->string, "no free address");
  630.         return;
  631.     }
  632.     d = od;
  633. assign:
  634.     d->net = ddp.srcNet;
  635.     d->node = ddp.srcNode;
  636.     d->timer = 1;
  637.     ig->ipaddress = (d - &ipdad[0]) + conf.ipaddr + conf.ipstatic + 1;
  638.     if (i == dmax)    /* if this address may have been reassigned */
  639.         arpdelete(ig->ipaddress);
  640. server:
  641.     ig->string[0] = 0;
  642.     ig->ipname = conf.ipname;
  643.     ig->ipbroad = conf.ipbroad;
  644.     ig->ipfile = conf.ipfile;
  645.     bcopy((caddr_t)conf.ipother, (caddr_t)ig->ipother, sizeof ig->ipother);
  646. }
  647.  
  648.  
  649. short    ipd_index, ipd_timer, ipd_first;    /* 'static' */
  650.  
  651. /*
  652.  * Timeout unused ipdad table entries.  Called once per second, sends
  653.  * one 'tickle' per minute to each 'active' IP address client.
  654.  * Sends at most one NBP per second.
  655.  */
  656. ipdadtimer()
  657. {
  658.     Entity ent;
  659.     register struct ipdad *d;
  660.  
  661.     if (conf.ipdynamic == 0)
  662.         return;
  663.     /*
  664.      * This one-time code runs between seconds 25 to 30 after the
  665.      * gateway is booted.  It does an nbplookup request for
  666.      * all IPADDRESSes so we can initially fill in our table.
  667.      */
  668.     if (ipd_first < 30) {
  669.         ipd_first++;
  670.         if (ipd_first < 25)    /* wait for RTMPs to establish */
  671.             return;
  672.         strcpy(ent.obj, "=");
  673.         strcpy(ent.type, "IPADDRESS");
  674.         strcpy(ent.zone, "*");
  675.         nbplookup(&ent, 0, 0);
  676.         return;
  677.     }
  678.     /*
  679.      * This code runs every second after startup.  Step thru
  680.      * the table pinging active entries.
  681.      */
  682.     ipd_timer++;
  683.     d = &ipdad[ipd_index];
  684.     for ( ; ; d++, ipd_index++) {
  685.         if (ipd_index >= conf.ipdynamic) {
  686.             if (ipd_timer < 60)
  687.                 return;
  688.             ipd_timer = ipd_index = 0;
  689.             d = &ipdad[0];
  690.         }
  691.         /* dont ping empty or really old entries */
  692.         if (d->timer == 0 ||  d->timer == ipdadTimerMax)
  693.             continue;
  694.         if (++d->timer > ipdadTimerMin)
  695.             continue;
  696.         iptoa(conf.ipaddr + conf.ipstatic + 1 + ipd_index, ent.obj);
  697.         strcpy(ent.type, "IPADDRESS");
  698.         strcpy(ent.zone, "*");
  699.         nbplookup(&ent, d->net, d->node);
  700.         ipd_index++;
  701.         return;
  702.     }
  703. }
  704.  
  705.  
  706. /*
  707.  * Reply to ipdadtimer NBP 'tickle' received; reset timer.
  708.  */
  709. ipdadreply(ifp, iaddr, daddr)
  710.     struct ifnet *ifp;
  711.     iaddr_t iaddr;
  712.     register AddrBlock *daddr;
  713. {
  714.     register struct ipdad *d;
  715.     register i;
  716.  
  717.     i = iaddr - (conf.ipaddr + conf.ipstatic + 1);
  718.     if (i < 0 || i >= conf.ipdynamic)
  719.         return;
  720.     d = &ipdad[i];
  721.     d->timer = 1;
  722.     d->net = daddr->net;
  723.     d->node = daddr->node;
  724. }
  725.  
  726.  
  727. /*
  728.  * Convert ASCII dot notation string 's' to long ip address.
  729.  * 'n' is optional byte count.
  730.  * Returns address, or 0 if error.
  731.  */
  732. atoip(s, n)
  733.     register char *s;
  734. {
  735.     register addr, dots, num;
  736.  
  737.     dots = addr = num = 0;
  738.     for ( ; ; s++, n--) {
  739.         if (n == 0 || *s == '.' || *s == 0) {
  740.             dots++;
  741.             if (num > 255)
  742.                 return (0);
  743.             addr = (addr << 8) + num;
  744.             num = 0;
  745.             if (n && *s == '.')
  746.                 continue;
  747.             if (dots != 4)
  748.                 return (0);
  749.             else
  750.                 return (addr);
  751.         }
  752.         if (*s >= '0' && *s <= '9')
  753.             num = (num*10) + (*s - '0');
  754.         else
  755.             return (0);
  756.     }
  757. }
  758.  
  759.  
  760. /*
  761.  * Convert IP address to ASCII.  Converts 'n' to string at 's'.
  762.  * Returns number of bytes in s (minus null).
  763.  */
  764. iptoa(n, s)
  765.     register n;
  766.     register char *s;
  767. {
  768.     char buf[20];
  769.     register char *cp;
  770.     int i;
  771.     register b;
  772.  
  773.     cp = buf;
  774.     for (i = 0 ; i < 4 ; i++) {
  775.         b = (n & 0xFF);
  776.         n >>= 8;
  777.         if (b) {
  778.             while (b) {
  779.                 *cp++ = (b % 10) + '0';
  780.                 b /= 10;
  781.             }
  782.         } else {
  783.             *cp++ = '0';
  784.         }
  785.         *cp++ = '.';
  786.     }
  787.     cp -= 2;    /* skip last dot */
  788.     i = 0;
  789.     while (cp >= buf) {
  790.         *s++ = *cp--;
  791.         i++;
  792.     }
  793.     *s = 0;
  794.     return (i);
  795. }
  796.  
  797.  
  798. /*
  799.  * Setup the standard IP header fields for a destination
  800.  */
  801. setiphdr(p, dst)
  802.     struct pbuf *p; 
  803.     iaddr_t dst;
  804. {
  805.     register struct ip *ip = (struct ip *)p->p_off;
  806.  
  807.     ip->ip_v = IPVERSION;
  808.     ip->ip_hl = sizeof(*ip) >> 2;
  809.     ip->ip_tos = 0;
  810.     ip->ip_len = p->p_len;
  811.     ip->ip_id = ipid++;
  812.     ip->ip_off = 0;
  813.     ip->ip_ttl = IPFRAGTTL;
  814.     ip->ip_p = IPPROTO_UDP;
  815.     ip->ip_src = conf.ipaddr;
  816.     ip->ip_dst = dst;
  817.     ip->ip_sum = 0;
  818.     ip->ip_sum = in_cksum((caddr_t)ip, sizeof(*ip));
  819. }
  820.  
  821.  
  822. /*
  823.  * assumes ddp.type already set and that the reply goes to the node specified
  824.  * by: (ddp.srcNet, ddp.srcNode, ddp.srcSkt)
  825.  *
  826.  * p should be aligned so offset points to start of lap data with room 
  827.  * for lap + long ddp.  p->p_len should record the correct length
  828.  *
  829.  * skt is outgoing socket
  830.  *
  831. */
  832. ddpreply(p, skt)
  833. register struct pbuf *p;
  834. int skt;
  835. {
  836.   u_char dst;
  837.   register struct DDP *dp = &ddp;
  838.  
  839.   dp->length = p->p_len - lapSize;
  840.   dp->checksum = 0;
  841.   dp->dstNet = dp->srcNet;
  842.   dp->dstNode = dp->srcNode;
  843.   dp->dstSkt = dp->srcSkt;
  844.   dp->srcNet = source_if->if_dnet;
  845.   dp->srcNode = source_if->if_dnode;
  846.   dp->srcSkt = skt;
  847.   bcopy((caddr_t)dp, p->p_off+lapSize, ddpSize);
  848.   routeddp(p, 0, 0);
  849. }
  850.